#include "Query.h"

Query* Query::instance = NULL;

Query::Query(){

}

Query* Query::getInstance() {
    if (instance == NULL)
        instance = new Query();
    return instance;
}

void Query::setTerminos(string term) {

    parseLine(term);
    if (tokens.size() == 0) {
        MainWindow::getInstance()->writeToStdOuT("Consulta no valida.");
        return;
    }

    this->i = new ArchivoAuxiliar("IndiceInvertido");    
    process();
    tokens.clear();    
    i->close();
    delete (i);
}

void Query::process(){
    vector<string>* terminos = this->i->getTerminos();   
    vector<string>::iterator termIterator = tokens.begin();
    vector<RegistroAuxiliar> registrosPosibles;

    while(termIterator != tokens.end()){
        int pos = Utils::binarySearch(terminos->begin(), terminos->end(),*termIterator);
        if (pos != -1) {
            RegistroAuxiliar *r = new RegistroAuxiliar();
            i->read(r, pos);
            i->close();
            delete(i);
            this->i = new ArchivoAuxiliar("IndiceInvertido");
            registrosPosibles.push_back(*r);
        }

        termIterator++;
    }

    if (registrosPosibles.size() < tokens.size()) {
        MainWindow::getInstance()->writeToStdOuT("No existen documentos en los cuales se encuentre la frase buscada.");
        return;
    }

    unsigned int min, pos = 0;
    vector<uint32_t> *docs, res;

    docs = (registrosPosibles.at(0)).getDocumentos();
    min = docs->size();

    for (unsigned int i = 1; i < registrosPosibles.size(); i++) {
        if ((registrosPosibles.at(i)).getDocumentos()->size() < min) {
            docs->clear();
            docs = (registrosPosibles.at(i)).getDocumentos();
            min = docs->size();
            pos = i;
        }
    }

    for (unsigned int i = 0; i < registrosPosibles.size(); i++) {
        if (i != pos) {
            unsigned int k = 0;
            vector<uint32_t> *docs1 = (registrosPosibles.at(i)).getDocumentos();

            for (unsigned int j = 0; j < docs->size(); j++) {
                while ((docs1->at(k) < docs->at(j)) && (k < docs1->size()-1))
                    k++;

                if (docs->at(j) == docs1->at(k))
                    res.push_back(docs->at(j));
            }

            docs->clear();
            docs1->clear();

            if (res.size() == 0) {
                MainWindow::getInstance()->writeToStdOuT("No existen documentos en los cuales se encuentre la frase buscada.");
                return;
            }

            for (unsigned int j = 0; j < res.size(); j++)
                docs->push_back(res.at(j));

            res.clear();
        }
    }

    ArchivoDocumentos *d = new ArchivoDocumentos("Docs.bin");

    bool inters = false;
    pos = 0;
    vector<uint32_t> pos1, pos2, pos3, pos4;

    for (unsigned int i = 0; i < docs->size(); i++) {
        pos1 = (registrosPosibles.at(0)).getPosiciones(docs->at(i));
        min = pos1.size();

        for (unsigned int j = 1; j < registrosPosibles.size(); j++) {
            if ((registrosPosibles.at(j)).getPosiciones(docs->at(i)).size() < min) {
                min = (registrosPosibles.at(j)).getPosiciones(docs->at(i)).size();
                pos1.clear();
                pos1 = (registrosPosibles.at(j)).getPosiciones(docs->at(i));                
                pos = j;
            }
        }

        for (unsigned int j = 0; j < pos1.size(); j++) {
            int m = pos1.at(j) - pos;
            if (m > 0)
                pos2.push_back(m);
        }

        pos1.clear();       

        for (unsigned int j = 0; j < registrosPosibles.size(); j++) {
            if (j != pos) {
                pos3 = (registrosPosibles.at(j)).getPosiciones(docs->at(i));

                for (unsigned int k = 0; k < pos3.size(); k++) {
                    int m = pos3.at(k) - j;
                    if (m > 0)
                        pos4.push_back(m);
                }

                pos3.clear();

                unsigned int x = 0;

                for (unsigned int k = 0; k < pos2.size(); k++) {
                    if (x == pos4.size()-1) {
                        if (pos4.at(x) == pos2.at(k))
                            res.push_back(pos2.at(k));
                        break;
                    }
                    while ((pos4.at(x) < pos2.at(k)) && (x < pos4.size()-1))
                        x++;

                    if (pos2.at(k) == pos4.at(x))
                        res.push_back(pos2.at(k));
                }

                pos2.clear();
                pos4.clear();

                if (res.size() == 0)
                    break;

                for (unsigned int k = 0; k < res.size(); k++) {
                    pos2.push_back(res.at(k));
                }

                res.clear();
            }
        }

        if (pos2.size() > 0) {
            MainWindow::getInstance()->writeToStdOuT(d->getPath(docs->at(i)));
            inters = true;
        }

        pos2.clear();
    }

    if (!inters)
        MainWindow::getInstance()->writeToStdOuT("No existen documentos en los cuales se encuentre la frase buscada.");
}

void Query::addToken(string term){
    tokens.push_back(term);
}

void Query::destroyInstance(){
    if(instance!=NULL){
        delete(instance);
        instance=NULL;
    }
}

Query::~Query(){
}
